package com.example.core.netty.processor;

import com.example.common.enums.ResponseCode;
import com.example.common.exception.BaseException;
import com.example.core.context.GatewayContext;
import com.example.core.context.HttpRequestWrapper;
import com.example.core.filter.FilterChainFactory;
import com.example.core.filter.GatewayFilterChainFactory;
import com.example.core.helper.RequestHelper;
import com.example.core.helper.ResponseHelper;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author Peng Yisheng
 * @Date 2024/11/14 0:27
 * @Description netty核心处理器
 */
@Slf4j
public class NettyCoreProcessor implements NettyProcessor {

    private FilterChainFactory filterChainFactory = GatewayFilterChainFactory.getInstance();

    @Override
    public void process(HttpRequestWrapper wrapper) {
        FullHttpRequest request = wrapper.getRequest();
        ChannelHandlerContext ctx = wrapper.getCtx();

        try {
            GatewayContext gatewayContext = RequestHelper.doContext(request, ctx);
            // 根据不同请求执行不同的过滤器链逻辑：默认过滤器 + 服务配置的过滤器
            filterChainFactory.buildFilterChain(gatewayContext).doFilter(gatewayContext);
        } catch (BaseException e) {
            log.error("process error {} {}", e.getCode().getCode(), e.getCode().getMessage());
            FullHttpResponse httpResponse = ResponseHelper.getHttpResponse(e.getCode());
            doWriteAndRelease(ctx, request, httpResponse);
        } catch (Throwable t) {
            log.error("process unkown error", t);
            FullHttpResponse httpResponse = ResponseHelper.getHttpResponse(ResponseCode.INTERNAL_ERROR);
            doWriteAndRelease(ctx, request, httpResponse);
        }
    }

    private void doWriteAndRelease(ChannelHandlerContext ctx, FullHttpRequest request, FullHttpResponse httpResponse) {
        ctx.writeAndFlush(httpResponse)
                .addListener(ChannelFutureListener.CLOSE); //释放资源后关闭channel
        ReferenceCountUtil.release(request);
    }

    @Override
    public void start() {

    }

    @Override
    public void shutDown() {

    }
}
